package de.lgohlke.collection;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import de.lgohlke.BenchmarkJob;
import de.lgohlke.BenchmarkRunner;
import de.lgohlke.compress.StringCompressorV2;

/**
 * <p>SimpleHashMapBenchmark class.</p>
 *
 * @author lars
 * @version $Id: $
 * @since 0.0.1
 */
public class SimpleHashMapBenchmark
{

  private static String[]                           dataKey;
  private static String[]                           dataValue;

  final int                                         loops = 1;
  private BenchmarkRunner                           runner;
  private HashMap<String, String>                   mapLegacy;
  private CompressedHashMap<String, String>         mapSingleCompress;
  private ParallelCompressedHashMap<String, String> mapMultiCompress2;
  private final List<Map<String, String>>           list  = new ArrayList<Map<String, String>>();

  /**
   * <p>main.</p>
   *
   * @param args an array of {@link java.lang.String} objects.
   */
  public static void main(final String[] args)
  {
    setup();

    SimpleHashMapBenchmark shb = new SimpleHashMapBenchmark();
    shb.beforeTest();
    shb.benchmarkFill();
    shb.showStats();
  }

  /**
   * <p>setup.</p>
   */
  @BeforeClass
  public static void setup()
  {
    int n = 1000;
    dataKey = new String[n];
    dataValue = new String[n];
    for (int i = 0; i < n; i++)
    {
      StringBuffer buffer = new StringBuffer(new Random().nextInt() + "");
      for (int j = 0; j < 5; j++)
      {
        buffer.append(buffer);
      }
      dataKey[i] = buffer.toString();

      buffer = new StringBuffer(new Random().nextInt() + "");
      for (int j = 0; j < 5; j++)
      {
        buffer.append(buffer);
      }
      dataValue[i] = buffer.toString();
    }
  }

  /**
   * <p>beforeTest.</p>
   */
  @Before
  public void beforeTest()
  {
    runner = BenchmarkRunner.createSerialBenchmarkRunner();
    runner.setLoops(loops);

    mapLegacy = new HashMap<String, String>();
    mapSingleCompress = new CompressedHashMap<String, String>().addKeyCompressor(new StringCompressorV2()).addValueCompressor(new StringCompressorV2());
    mapMultiCompress2 = new ParallelCompressedHashMap<String, String>(mapSingleCompress);

    list.clear();
    list.add(mapLegacy);
    list.add(mapSingleCompress);
    // list.add(mapMultiCompress);
    list.add(mapMultiCompress2);
  }

  /**
   * <p>showStats.</p>
   */
  @After
  public void showStats()
  {
    runner.showStats();
    mapSingleCompress.printStats();
    mapMultiCompress2.printStats();
  }

  /**
   * <p>benchmarkFill.</p>
   */
  @Test
  public void benchmarkFill()
  {
    System.out.println("Fill");
    for (Map<String, String> m : list)
    {
      runner.enqueueJob(createJobFill(m));
    }
  }

  /**
   * <p>benchmarkFillAndClear.</p>
   */
  @Test
  public void benchmarkFillAndClear()
  {
    System.out.println("FillAndClear");
    for (Map<String, String> m : list)
    {
      runner.enqueueJob(createJobFillAndClear(m));
    }
  }

  /**
   * <p>benchmarkFillAndClearAndKeySet.</p>
   */
  @Test
  public void benchmarkFillAndClearAndKeySet()
  {
    System.out.println("FillAndClearAndKeySet");
    for (Map<String, String> m : list)
    {
      runner.enqueueJob(createJobFillAndKeySet(m));
    }
  }

  /**
   * <p>benchmarkFillAndClearAndKeySetAndValueSet.</p>
   */
  @Test
  public void benchmarkFillAndClearAndKeySetAndValueSet()
  {
    System.out.println("FillAndClearAndKeySetAndValueSet");
    for (Map<String, String> m : list)
    {
      runner.enqueueJob(createJobFillAndKeySetAndValueSet(m));
    }
  }

  /**
   * <p>benchmarkFillAndClearAndKeySetAndValueSetAndGetAll.</p>
   */
  @Test
  public void benchmarkFillAndClearAndKeySetAndValueSetAndGetAll()
  {
    System.out.println("FillAndClearAndKeySetAndValueSetAndGetAll");
    for (Map<String, String> m : list)
    {
      runner.enqueueJob(createJobFillAndKeySetAndValueSetAndGetAll(m));
    }
  }

  private BenchmarkJob createJobFill(final Map<String, String> map)
  {
    return new BenchmarkJob()
    {

      public void run()
      {
        map.clear();

        for (int i = 0; i < dataKey.length; i++)
        {
          map.put(dataKey[i], dataValue[i]);
        }

        if (map instanceof ParallelCompressedHashMap)
        {
          ((ParallelCompressedHashMap) map).flush();
        }
      }

      public String getName()
      {
        return map.getClass().getSimpleName();
      }
    };
  };

  private BenchmarkJob createJobFillAndClear(final Map<String, String> map)
  {
    return new BenchmarkJob()
    {

      public void run()
      {
        map.clear();

        for (int i = 0; i < dataKey.length; i++)
        {
          map.put(dataKey[i], dataValue[i]);
        }

        map.clear();
        if (map instanceof ParallelCompressedHashMap)
        {
          ((ParallelCompressedHashMap) map).flush();
        }
      }

      public String getName()
      {
        return map.getClass().getSimpleName();
      }
    };
  };

  private BenchmarkJob createJobFillAndKeySet(final Map<String, String> map)
  {
    return new BenchmarkJob()
    {

      public void run()
      {
        map.clear();

        for (int i = 0; i < dataKey.length; i++)
        {
          map.put(dataKey[i], dataValue[i]);
        }

        map.keySet();
        if (map instanceof ParallelCompressedHashMap)
        {
          ((ParallelCompressedHashMap) map).flush();
        }
      }

      public String getName()
      {
        return map.getClass().getSimpleName();
      }
    };
  };

  private BenchmarkJob createJobFillAndKeySetAndValueSet(final Map<String, String> map)
  {
    return new BenchmarkJob()
    {

      public void run()
      {
        map.clear();

        for (int i = 0; i < dataKey.length; i++)
        {
          map.put(dataKey[i], dataValue[i]);
        }

        map.keySet();
        map.values();
        if (map instanceof ParallelCompressedHashMap)
        {
          ((ParallelCompressedHashMap) map).flush();
        }
      }

      public String getName()
      {
        return map.getClass().getSimpleName();
      }
    };
  };

  private BenchmarkJob createJobFillAndKeySetAndValueSetAndGetAll(final Map<String, String> map)
  {
    return new BenchmarkJob()
    {

      public void run()
      {
        map.clear();

        for (int i = 0; i < dataKey.length; i++)
        {
          map.put(dataKey[i], dataValue[i]);
        }

        map.keySet();
        map.values();

        for (String item : dataKey)
        {
          map.get(item);
        }

        if (map instanceof ParallelCompressedHashMap)
        {
          ((ParallelCompressedHashMap) map).flush();
        }
      }

      public String getName()
      {
        return map.getClass().getSimpleName();
      }
    };
  };
}
